/*
 * Copyright (c) 2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.libermundi.theorcs.core.tapestry.services.assets;

import java.net.URL;

import org.apache.tapestry5.internal.services.ContextResource;
import org.apache.tapestry5.ioc.Resource;
import org.apache.tapestry5.ioc.internal.util.AbstractResource;
import org.apache.tapestry5.ioc.internal.util.ClasspathResource;
import org.apache.tapestry5.services.Context;
import org.libermundi.theorcs.core.util.StringListUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OfsResource extends AbstractResource {
	
	private static final Logger logger = LoggerFactory.getLogger(OfsResource.class);
	
	private ClassLoader _classLoader;
	private Context _context;
	private String _localInstallPath;
	private Resource _resolvedResource;

	public OfsResource(Context context, String localInstallPath, String relativePath) {
		super(relativePath.replaceAll("\\\\", "/")); //For Windows System
    	_classLoader = Thread.currentThread().getContextClassLoader();
    	_context = context;
    	_localInstallPath= localInstallPath.replaceAll("\\\\", "/"); //For Windows System;
    	_resolvedResource = resolveResource();
    	if(logger.isDebugEnabled()) {
    		logger.debug("Building new OfsResource for : [" + getPath() + "] in [" + localInstallPath +"]"); 
    	}
    }	

	private Resource resolveResource() {
		Resource r = null;
		if(logger.isDebugEnabled()) {
			logger.debug("Trying to resolve Resource : " + getPath()); 
		}
		
		if(getPath().isEmpty()) {
			return null;
		}
		
		//We check first is the resource exists in the localInstallPath
		if(StringListUtils.listFirst(_localInstallPath, ":").equals("classpath")) {
			// Here it means the user can put its own files in META-INF folder
			// Within deployment path
			r = new ClasspathResource(_localInstallPath + OfsAssetFactory.OFS_RESOURCE_FOLDER + getCleanPath());
			if(r.exists()) {
				if(logger.isInfoEnabled()){
					logger.info("Resolved '" + getPath() + "' to ClassPathResource : " + r.toURL()); 
				}
				return r; 
			}
		}
		
		if(StringListUtils.listFirst(_localInstallPath, ":").equals("file")) {
			// Here it means the user can put its own files in external folder
			r = new FileResource(_localInstallPath + OfsAssetFactory.OFS_RESOURCE_FOLDER + getCleanPath());
			if(r.exists()) {
				if(logger.isInfoEnabled()){
					logger.info("Resolved '" + getPath() + "' to FileResource : " + r.toURL()); 
				}
				return r; 
			}
		}

		// At this point it seems that the file is not in the LocalInstallPath
		// Let's check in the Context ( WEB-INF folder )
		r = new ContextResource(_context, OfsAssetFactory.DEFAULT_CONTEXT_LOCATION + OfsAssetFactory.OFS_RESOURCE_FOLDER + getCleanPath());
		if(r.exists()) {
			if(logger.isInfoEnabled()){
				logger.info("Resolved '" + getPath() + "' to Default ContextResource : " + r.toURL()); 
			}
			return r; 
		}
		
		// Let's check in the Context ( WEB-INF folder )
		r = new ClasspathResource(_classLoader, OfsAssetFactory.DEFAULT_CLASSPATH_LOCATION + OfsAssetFactory.OFS_RESOURCE_FOLDER + getCleanPath());
		if(r.exists()) {
			if(logger.isInfoEnabled()){
				logger.info("Resolved '" + getPath() + "' to Default ClasspathResource : " + r.toURL()); 
			}
			return r; 
		}
		
		return r;
	}
	
	private String getCleanPath() {
		String path = getPath();
		if(path.startsWith("/")) {
			return path.substring(1);
		}
		return path;
		
	}

	@Override
	public URL toURL() {
		if(_resolvedResource == null) {
			return null;
		}
		return _resolvedResource.toURL();
	}


	@Override
	protected Resource newResource(String path) {
		return new OfsResource(_context, _localInstallPath, path);
	}

	@Override
	public boolean exists() {
		if(_resolvedResource == null) {
			return Boolean.FALSE;
		}
		return _resolvedResource.exists();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime
				* result
				+ ((_resolvedResource == null) ? 0 : _resolvedResource
						.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		OfsResource other = (OfsResource) obj;
		if (_resolvedResource == null) {
			if (other._resolvedResource != null) {
				return false;
			}
		} else if (!_resolvedResource.equals(other._resolvedResource)) {
			return false;
		}
		return true;
	}

	@Override
	public String toString() {
		String msg = (_resolvedResource!=null && _resolvedResource.exists()) ?_resolvedResource.toURL().toString():"Not Resolved";
		return "OfsResource [Path : "+ getPath() + " // ResolvedResource : " + msg + "]";
	}

}
